package com.ljh.mybatis.mapper;

import com.ljh.mybatis.model.UserInfo;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface UserInfoMapper {
    // ! 直接查询会导致：当类属性名和字段名匹配不上时，导致查询出来的值是null
    // ? 可以在 sql 语句上给字段起别名，可以解决
    // ? 也可以使用 @Results 和 @Result 注解可以解决
//    @Results({
//            @Result(column = "delete_flag", property = "deleteFlag"),
//            @Result(column = "create_time", property = "createTime"),
//            @Result(column = "update_time", property = "updateTime")
//    })
//    @Select("select * from user_info")
//    List<UserInfo> selectAll();

    // ! 单纯地使用会导致每个地方都需要加上 @Results 和 @Result 注解
    // ? 给 @Results 加上 id 便可以达到复用的效果
    @Results(id = "1", value = {
            @Result(column = "delete_flag", property = "deleteFlag"),
            @Result(column = "create_time", property = "createTime"),
            @Result(column = "update_time", property = "updateTime")
    })
    @Select("select * from user_info")
    List<UserInfo> selectAll();


    // ? 使用 @ResultMap 可以使用有 id 的 @Results，以达到复用的效果
    // ! 实际发现，这样写还是太麻烦，于是乎直接在配置文件直接配置就好，详情请看 application.yml
    @ResultMap(value = "1")
    @Select("select * from user_info where id = #{id}")
    UserInfo selectAllById(Integer id);

    // ? 但只有一个参数时，参数名不一也可以识别
    @Select("select * from user_info where id = #{a}")
    UserInfo selectAllById2(@Param("a") Integer id); // ! 使用 @Params 注解给变量名起别名

    @Select("select * from user_info where username = #{username} and `password` = #{password}")
    List<UserInfo> selectByNameAndPassword(String username, String password);

    @Insert("insert into user_info (username, `password`, age) values (#{username}, #{password}, #{age})")
    Integer insertUser(UserInfo userInfo);

    // ? 通过使用 @Options 注解可以在使用该方法的位置拿到 keyProperty 指定的字段
    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("insert into user_info (username, `password`, age) values (#{userInfo.username}, #{userInfo.password}, #{userInfo.age})")
    Integer insertUser2(@Param("userInfo") UserInfo userInfo);

    @Delete("delete from user_info where id = #{id}")
    Integer deleteUser(Integer id);

    @Update("update user_info set delete_flag = #{deleteFlag}, phone = #{phone} where id = #{id}")
    Integer updateUser(UserInfo userInfo);

    // ? #{} 是预编译的，也就是 预编译SQL，MyBatis 会将 #{} 替换成占位符(比如 ?)，并将参数值作为预编译语句的参数传入，从而提高了SQL语句的执行效率。
    // ? ${} 不是预编译的，也就是 即时SQL，MyBatis 会直接将 ${} 替换成参数值，拼接到 SQL 语句中，可能导致SQL语句的重复编译和执行，影响性能。
    // ! 所以在使用 ${} 时，通常加上 '' 表示其为字符串
    @Select("select * from user_info where username ='${username}' and `password` = '${password}'")
    List<UserInfo> selectByNameAndPassword2(String username, String password);

    // ? 使用 #{} 可以防范 SQL 注入攻击，因为 MyBatis 会将参数值进行预编译，将其作为 SQL 语句的参数传入，而不是直接将参数值拼接到 SQL 语句中。
    // ? 使用 ${} 时，参数值会直接替换 SQL 语句中的 ${} 占位符，存在 SQL 注入的风险，尤其是当参数值来自用户输入时，应谨慎使用 ${}
    // ! 并非完全要杜绝 ${} 的使用，在需要排序功能、模糊查询、表名、字段名作为参数时，使用 #{} 不能完成
    @Select("select * from user_info order by id ${orderBy}")
    List<UserInfo> selectAll2(String orderBy);
    // ! 虽然换成 ${} 可以解决问题，但由于 ${} 存在 SQL 注入的问题，所以推荐使用 MySQL 自带的函数 concat() 解决
    @Select("select * from user_info where username like concat('%', #{username}, '%')")
    List<UserInfo> selectAll3(String username);
}
